home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 2002 November
/
SGI Freeware 2002 November - Disc 2.iso
/
dist
/
fw_gnome-pilot.idb
/
usr
/
freeware
/
share
/
gob
/
gnome-pilot-conduit-management.gob.z
/
gnome-pilot-conduit-management.gob
Wrap
Text File
|
2001-10-09
|
18KB
|
651 lines
/* gnome-pilot-conduit-management.gob
*
* Copyright (C) 1999-2000 Free Software Foundation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors: Eskil Heyn Olsen <eskil@eazel.com>
*/
/* GOB version requirement */
requires 0.92.4
/*
Design notes :
Data containment will be split into two ;
1) The GnomePilotConduitManagement object, which is the one users
will access. Through this, they can query attributes and
instantiate the conduit.
This will also carry all non-static info
(ie. info not found in the .conduit files)
2) GnomePilotConduitMgmtData structs, which are the internally kept
structures containing what was read from the .conduit files.
*/
%h{
#include <glib.h>
#include <gtk/gtkobject.h>
#include <gpilotd/gnome-pilot-conduit.h>
#include <gmodule.h>
#ifdef DLOPEN_TEST
#include <dlfcn.h>
#endif
enum GnomePilotConduitMgmtError {
GNOME_PILOT_CONDUIT_MGMT_OK,
GNOME_PILOT_CONDUIT_MGMT_ALREADY_LIVE,
GNOME_PILOT_CONDUIT_MGMT_ERROR,
GNOME_PILOT_CONDUIT_MGMT_FATAL
};
enum GnomePilotConduitType {
GNOME_PILOT_CONDUIT_TYPE_SHLIB,
};
enum GnomePilotConduitFilter {
GNOME_PILOT_CONDUIT_MGMT_ID=0,
GNOME_PILOT_CONDUIT_MGMT_NAME
};
typedef struct _GnomePilotConduitMgmtData GnomePilotConduitMgmtData;
struct _GnomePilotConduitMgmtData {
/* The id of the conduit */
gchar *id;
/* The locale name of the conduit */
gchar *name;
/* The type of the conduit, sharedlib or whatgives */
enum GnomePilotConduitType type;
/* Where the conduit cab be found */
gchar *location;
/* A hash of all attributes of type string, note
the local translation overwrites others. */
GHashTable *string_attributes;
};
%}
%{
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <gnome-xml/tree.h>
#include <gnome-xml/parser.h>
/*
MT-Level :
Change these defines to make the lib MT safe.
(UN)LOCK_MY_HASHES should mutex the conduitname_to_datastruct hash
(UN)LOCK_MY_COUNTER should mutex the number_of_instances counter
(UN)LOCK_INSTANCE should mutex the current Gnome:Pilot:Conduit:Management instance
uhm, don't think I'll use LOCK_INSTANCE
*/
#define LOCK_MY_COUNTER
#define UNLOCK_MY_COUNTER
#define LOCK_MY_HASHES
#define UNLOCK_MY_HASHES
#define LOCK_INSTANCE
#define UNLOCK_INSTANCE
/* the version that the conduit xml spec files should have */
#define CONDUIT_XML_VERSION "1.0"
gboolean initialized = FALSE;
int number_of_instances = 0;
GHashTable *conduitname_to_datastruct;
GHashTable *conduitid_to_datastruct;
/* these are the list of valid tags in addition to conduit-attribute */
static const gchar *valid_tags[] = {"conduit","name",NULL};
%}
class Gnome:Pilot:Conduit:Management from Gtk:Object {
/* TRUE if the module is loaded can be used for sync. */
private gboolean loaded;
/* if loaded==TRUE, this is the GModule handler */
private GModule *dlhandle;
/* if loaded==TRUE, these are the load/destroy funcs
loaded from the object */
private GnomePilotConduitLoadFunc load_func;
private GnomePilotConduitDestroyFunc destroy_func;
/* This is a pointer to a MgmtData object returned from
conduitname_to_datastruct or conduitid_to_datastruct hashes */
private GnomePilotConduitMgmtData *mgmtdata;
/***************************/
/* Initialization */
/***************************/
/* This reads the .conduit files and loads the hashes */
private void
initializer(void) {
if (!initialized) {
struct dirent **namelist;
int dirs;
g_message("reading .conduit's from %s",CONDUITDIR);
/* Do read of all .conduit files here */
LOCK_MY_HASHES;
conduitname_to_datastruct = g_hash_table_new(g_str_hash,g_str_equal);
conduitid_to_datastruct = g_hash_table_new(g_str_hash,g_str_equal);
dirs = scandir(CONDUITDIR,
&namelist,
(int (*)(const struct dirent*))gnome_pilot_conduit_management_select_dir_entry,
alphasort);
/* g_message("direntries = %d",dirs); */
for (; dirs>0;dirs--) {
GnomePilotConduitMgmtData *conduitdata;
conduitdata = read_conduit_xml(namelist[dirs-1]->d_name);
}
UNLOCK_MY_HASHES;
}
initialized = TRUE;
}
/* This loads a conduit of a specific type */
public GnomePilotConduitManagement*
new(gchar *_name (check null), enum GnomePilotConduitFilter filter)
onerror NULL
{
GtkObject *ret = NULL;
GHashTable *which_to_use = NULL;
GnomePilotConduitManagement *obj = NULL;
GnomePilotConduitMgmtData *_mgmtdata = NULL;
LOCK_MY_COUNTER;
if (number_of_instances==0) {
gnome_pilot_conduit_management_initializer();
}
number_of_instances++;
UNLOCK_MY_COUNTER;
switch (filter) {
case GNOME_PILOT_CONDUIT_MGMT_ID:
which_to_use = conduitid_to_datastruct;
break;
case GNOME_PILOT_CONDUIT_MGMT_NAME:
which_to_use = conduitname_to_datastruct;
break;
}
_mgmtdata = g_hash_table_lookup(which_to_use,_name);
if (_mgmtdata) {
ret = GTK_OBJECT(GET_NEW);
obj = SELF(ret);
obj->_priv->loaded = FALSE;
obj->_priv->mgmtdata = _mgmtdata;
} else {
g_warning("Unknown conduit, name=\"%s\"",_name);
}
return obj;
}
/* Destroys this instance of self
FIXME: dealloc all the loaded !!
*/
public void
destroy(self) {
LOCK_INSTANCE;
LOCK_MY_COUNTER;
number_of_instances--;
if (number_of_instances==0) {
/* g_message("No more instances"); */
}
gtk_object_destroy(GTK_OBJECT(self));
UNLOCK_MY_COUNTER;
UNLOCK_INSTANCE;
}
/***************************/
/* XML LOADING */
/***************************/
/* Used for scandir, checks that entry ends in .conduit
and is not a dir. */
private int
select_dir_entry(struct dirent *de) {
gchar *ptr;
struct stat st;
if (de==NULL || de->d_name==NULL) return 0;
/* g_message("select_dir_entry(%s)",de->d_name); */
if (strlen(de->d_name) < strlen(".conduit")) return 0;
ptr = de->d_name;
ptr += strlen(de->d_name) - strlen(".conduit");
if (strcmp(ptr,".conduit")) return 0;
ptr = g_strdup_printf("%s%s",CONDUITDIR,de->d_name);
stat(ptr,&st);
if (S_ISDIR(st.st_mode) ||
S_ISCHR(st.st_mode) ||
S_ISFIFO(st.st_mode) ||
S_ISSOCK(st.st_mode)) return 0;
g_message("select_dir_entry(%s)",de->d_name);
return 1;
}
/* Checks wether a tag is in the valid_tags list */
private gboolean
is_other_valid_tag(const gchar *s) {
gint i = 0;
for (i=0;valid_tags[i];i++)
if (g_strcasecmp(s,valid_tags[i])==0) return TRUE;
return FALSE;
}
/* This reads the XML header, and creates a new
GnomePilotConduitMgmt if ok, otherwise returns NULL */
private GnomePilotConduitMgmtData*
check_xml_version(xmlNodePtr root) {
GnomePilotConduitMgmtData *ret;
xmlChar *version;
version = xmlGetProp(root,"version");
/* g_message("version = %s",version); */
if (version==NULL || g_strcasecmp(version,CONDUIT_XML_VERSION)!=0) {
g_warning("incompatible version");
return NULL;
}
/* g_message("XML version is ok, creating entry"); */
ret = g_new(GnomePilotConduitMgmtData,1);
ret->string_attributes = g_hash_table_new(g_str_hash,g_str_equal);
return ret;
}
/* This loads the <conduit type=... location=...> stuff */
private gboolean
read_conduit_topdata(GnomePilotConduitMgmtData *obj, xmlNodePtr root) {
xmlNodePtr node;
xmlChar *type,*location,*id_string;
node = root->childs;
/* until we find the "conduit" node */
while (node && g_strcasecmp(node->name,"conduit")!=0) {
node = node->next;
}
if (!node) {
g_warning("error in XML, missing the \"conduit\" node");
return FALSE;
}
type = xmlGetProp(node,"type");
location = xmlGetProp(node,"location");
id_string = xmlGetProp(node,"id");
if (id_string==NULL) {
g_warning("error in XML, missing id_string");
return FALSE;
} else {
if (strchr(id_string,' ')) {
g_warning("error in XML, id_string bad");
return FALSE;
}
}
if (location==NULL) {
g_warning("error in XML, missing location");
return FALSE;
}
if(g_strcasecmp(type,"shlib")==0) {
obj->type = GNOME_PILOT_CONDUIT_TYPE_SHLIB;
} else {
g_warning("Unknown conduit type");
return FALSE;
}
obj->location = g_strdup(location);
obj->id = g_strdup(id_string);
g_hash_table_insert(conduitid_to_datastruct,
obj->id,
obj);
return TRUE;
}
/* This loads the correct <name ...> tag, taking the correct i18n */
private gboolean
read_conduit_name(GnomePilotConduitMgmtData *obj, xmlNodePtr root) {
xmlNodePtr node;
xmlChar *value,*lang;
gchar *current_name=NULL;
node = root->childs;
/* until we find a name node */
while (node) {
while (node && g_strcasecmp(node->name,"name")) {
node = node->next;
}
if (node) {
value = xmlGetProp(node,"value");
lang = xmlGetProp(node,"lang");
/* if this is a default name, and there
is no current_name, set it. If on the
other hand there is a lang, and it's the current, set it*/
if ((!lang && !current_name) ||
(lang && gnome_i18n_get_language() && g_strcasecmp(lang,gnome_i18n_get_language())==0)) {
if (current_name) g_free(current_name);
current_name = g_strdup(value);
}
node = node->next;
}
}
if (!current_name) {
g_warning("could not determine name from XML");
return FALSE;
}
obj->name = g_strdup(current_name);
g_hash_table_insert(conduitname_to_datastruct,
obj->name,
obj);
return TRUE;
}
/* When this is called, HASHES should be locked */
/* Reads the attributes from the XML file */
private void
read_conduit_attributes(GnomePilotConduitMgmtData *obj, xmlNodePtr root) {
xmlNodePtr node;
/* loop over the children */
for (node = root->childs; node!=NULL; node=node->next) {
if (g_strcasecmp(node->name,"conduit-attribute")==0) {
xmlChar *lang,*name,*type,*value;
gchar *attr_with_lang;
lang = xmlGetProp(node,"lang");
name = xmlGetProp(node,"name");
type = xmlGetProp(node,"type");
value = xmlGetProp(node,"value");
if (value==NULL) {
g_warning("attribute has no value");
continue;
}
if (name==NULL) {
g_warning("attribute has no name");
continue;
}
/* g_message("conduit-attribute [%s-%s] is \"%s\"/%s",
name,lang,value,type); */
if (lang) {
attr_with_lang = g_strdup_printf("%s##%s",
lang,name);
} else {
attr_with_lang = g_strdup(name);
}
/* if no type, assume string */
if(type==NULL || g_strcasecmp(type,"string")==0) {
g_hash_table_insert(obj->string_attributes,
attr_with_lang,
g_strdup(value));
} else {
g_warning("Unknown type %s",type);
}
} else if (!is_other_valid_tag(node->name)) {
g_warning("node->name = \"%s\", unhandled ",node->name);
}
}
}
/* When this is called, HASHES should be locked */
/* Open and checks the xml file */
private GnomePilotConduitMgmtData*
read_conduit_xml(gchar *fname) {
gchar *name;
xmlDocPtr doc;
xmlNodePtr root;
GnomePilotConduitMgmtData *ret;
name = g_strdup_printf("%s%s",CONDUITDIR,fname);
/* g_message("read_conduit_xml: reading from %s",name); */
/* load the thing */
doc = xmlParseFile(name);
/* check validity 1 */
if(!doc->root ||
!doc->root->name ||
g_strcasecmp(doc->root->name,"gnome-pilot-conduit")!=0) {
xmlFreeDoc(doc);
return NULL;
}
root = doc->root;
ret = check_xml_version(root);
if (!read_conduit_topdata(ret,root) ||
!read_conduit_name(ret,root)) {
g_hash_table_destroy(ret->string_attributes);
g_free(ret);
xmlFreeDoc(doc);
return NULL;
}
;
read_conduit_attributes(ret,root);
xmlFreeDoc(doc);
return ret;
}
/***************************/
/* ATTRIBUTE QUERYING */
/***************************/
/* returns the local name of the conduit */
public const gchar*
get_name(self) {
return self->_priv->mgmtdata->name;
}
/* returns the id of the conduit */
public const gchar*
get_id(self) {
return self->_priv->mgmtdata->id;
}
/* this takes a name and the data, appends the name to the output */
private void
hfunc_build_name_list(gchar *name, GnomePilotConduitMgmtData *data, GList **output) {
(*output) = g_list_append(*output,name);
}
public gint
get_conduits(GList **output (check null),enum GnomePilotConduitFilter filter)
onerror GNOME_PILOT_CONDUIT_MGMT_ERROR
{
GHashTable *which_to_use = NULL;
gnome_pilot_conduit_management_initializer();
LOCK_MY_HASHES;
switch (filter) {
case GNOME_PILOT_CONDUIT_MGMT_ID:
which_to_use = conduitid_to_datastruct;
break;
case GNOME_PILOT_CONDUIT_MGMT_NAME:
which_to_use = conduitname_to_datastruct;
break;
}
g_hash_table_foreach(which_to_use,
(GHFunc)hfunc_build_name_list,
output);
UNLOCK_MY_HASHES;
return GNOME_PILOT_CONDUIT_MGMT_OK;
}
/* used to retrieve all attribute keys */
private
void attribs_foreach(gchar *key, gpointer unused, GList **l) {
(*l) = g_list_append(*l,key);
}
/* used to retrieve all attribute keys without the lang code */
private
void attribs_filter_lang_foreach(gchar *key, gpointer unused, GList **l) {
if (!strstr(key,"##"))
(*l) = g_list_append(*l,key);
}
/* Returns all the available attributes
who are on the form <name>[##<lang>]
if filter_lang = TRUE, the lang is removed
*/
public GList*
get_attribute_list(self,gboolean filter_lang) {
GList *attribs = NULL;
LOCK_MY_HASHES;
if (filter_lang) {
g_hash_table_foreach(self->_priv->mgmtdata->string_attributes,(GHFunc)attribs_filter_lang_foreach,&attribs);
} else {
g_hash_table_foreach(self->_priv->mgmtdata->string_attributes,(GHFunc)attribs_foreach,&attribs);
}
UNLOCK_MY_HASHES;
return attribs;
}
/* Gets an attribute. Lang is the preferred language
for the attribute, NULL causes gnome_i18n_get_language() to be used */
public const gpointer*
get_attribute(self,
gchar *attribute_name (check null),
gchar *lang)
onerror NULL
{
gpointer *attr = NULL;
gchar *attribute_name_with_lang;
LOCK_MY_HASHES;
/* if no such conduit, do nothing and NULL will be returned */
if (strstr(attribute_name,"##")==NULL) {
attribute_name_with_lang = g_strdup_printf("%s##%s",
lang?lang:gnome_i18n_get_language(),
attribute_name);
} else {
attribute_name_with_lang = g_strdup(attribute_name);
}
attr = g_hash_table_lookup(self->_priv->mgmtdata->string_attributes,
attribute_name_with_lang);
g_free(attribute_name_with_lang);
if (!attr) {
/* no luck, try without language */
attr = g_hash_table_lookup(self->_priv->mgmtdata->string_attributes,attribute_name);
}
UNLOCK_MY_HASHES;
return attr;
}
/***************************/
/* CONDUIT ACTIVATION */
/***************************/
/* opener for shlib conduits
opens the conduit and loads the func, preparing it
for use */
private gint
shlib_loader(self) {
gchar *location = self->_priv->mgmtdata->location;
GModule *dlhandle = self->_priv->dlhandle;
if (g_module_supported()!=TRUE) {
g_warning(_("module loading not supported, fatal!"));
return GNOME_PILOT_CONDUIT_MGMT_FATAL;
}
if ((dlhandle = g_module_open(location,0))==NULL) {
g_warning("unable to g_module_open(%s), reason %s", location, g_module_error ());
#ifdef DLOPEN_TEST
{
void *handle;
g_warning ("doing dlopen_test");
handle = dlopen (location, RTLD_LAZY);
if (handle == NULL) {
g_message ("dlopen error is %s",dlerror());
}
dlclose (handle);
}
#endif
return GNOME_PILOT_CONDUIT_MGMT_ERROR;
}
if (g_module_symbol(dlhandle,"conduit_get_gpilot_conduit",
(gpointer)&(self->_priv->load_func))==FALSE) {
g_warning("malformed conduit, cannot locate symbol"
"\"conduit_get_gpilot_conduit\", error %s",
g_module_error());
return GNOME_PILOT_CONDUIT_MGMT_ERROR;
}
if (g_module_symbol(dlhandle,"conduit_destroy_gpilot_conduit",
(gpointer)&(self->_priv->destroy_func))==FALSE) {
g_warning("malformed conduit, cannot locate symbol"
"\"conduit_destroy_gpilot_conduit\", error %s",
g_module_error());
return GNOME_PILOT_CONDUIT_MGMT_ERROR;
}
self->_priv->loaded = TRUE;
return GNOME_PILOT_CONDUIT_MGMT_OK;
}
/* Loads the conduit and creates an instance for
the specified pilot
Returns
*/
public gint
instantiate_conduit(self, guint pilot_id, GnomePilotConduit **instance (check null))
onerror GNOME_PILOT_CONDUIT_MGMT_ERROR
{
gint err = GNOME_PILOT_CONDUIT_MGMT_OK;
(*instance) = NULL;
LOCK_INSTANCE;
if (self->_priv->loaded==FALSE) {
switch(self->_priv->mgmtdata->type) {
case GNOME_PILOT_CONDUIT_TYPE_SHLIB:
err = shlib_loader(self);
break;
default:
g_warning("unknown conduit type");
break;
}
}
if (err == GNOME_PILOT_CONDUIT_MGMT_OK) {
(*instance) = self->_priv->load_func(pilot_id);
}
UNLOCK_INSTANCE;
return err;
}
/* Destroys the conduit instance */
public gint
destroy_conduit(self, GnomePilotConduit **instance (check null))
onerror GNOME_PILOT_CONDUIT_MGMT_ERROR
{
LOCK_INSTANCE;
if (self->_priv->loaded==TRUE) {
self->_priv->destroy_func(*instance);
}
UNLOCK_INSTANCE;
return GNOME_PILOT_CONDUIT_MGMT_OK;
}
}
%{
%}